package top.suven.base.core.redis.cluster;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import top.suven.base.core.redis.RedisClusterEnum;
import top.suven.base.util.constants.GlobalConstants;
import top.suven.base.util.utilize.JsonUtils;

import java.util.HashSet;
import java.util.Set;

@Configuration
@EnableConfigurationProperties(RedisConfigSettings.class)
@ConditionalOnProperty(name = GlobalConstants.REDIS_AUTO_CONFIG_ENABLED,  matchIfMissing = true)
@ConfigurationProperties
public class RedisAutoConfiguration implements RedisConfig, EnvironmentAware, BeanDefinitionRegistryPostProcessor {
	private final Logger logger = LoggerFactory.getLogger(RedisAutoConfiguration.class);

	private RedisConfigSettings redisConfigSettings;
	private Binder binder;

	@Override
	public void setEnvironment(Environment environment) {
 		binder = Binder.get(environment);
		redisConfigSettings = binder.bind(REDIS_AUTO_CONFIG_PREFIX, RedisConfigSettings.class).get();
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

	}


	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

		Set<RedisClusterEnum> sourceNames = new HashSet<>();
		sourceNames.addAll(RedisClusterEnum.getRedisClusters());
		logger.info("start redis sourceNames={}",sourceNames==null?"": JsonUtils.toJsonString(sourceNames));
		if (sourceNames == null || sourceNames.isEmpty()) {
			return;
		}

		for (RedisClusterEnum beanName : sourceNames) {

			String servers = this.getProperty(REDIS_CLUSTER_SERVERS,beanName);
			if(servers == null){
				continue;
			}
			String password =this.getProperty(REDIS_CLUSTER_PASSWORD,beanName);

 			BeanDefinitionBuilder redisFactoryDefinition = BeanDefinitionBuilder
					.genericBeanDefinition(RedisClusterClientFactory.class);
			redisFactoryDefinition.addPropertyValue(REDIS_CLUSTER_PARAM_SERVER, servers);
			redisFactoryDefinition.addPropertyValue(REDIS_CLUSTER_PARAM_PASSWORD, password);

			redisFactoryDefinition.addPropertyValue(REDIS_CLUSTER_PARAM, redisConfigSettings);



			registry.registerBeanDefinition(beanName.getValue(), redisFactoryDefinition.getBeanDefinition());
			logger.info("start redis cluster bean=[{}],definition=[{}]",beanName.getValue(),redisFactoryDefinition.getBeanDefinition());
			logger.warn("RedisAutoConfiguration BeanDefinitions=[{}] Registry --- routingRedisCluster Successfully ...      ",beanName.getValue());
		}

	}

	private String getProperty(String prefix, RedisClusterEnum beanName){
		StringBuilder sb = new StringBuilder(prefix);
		if(beanName != RedisClusterEnum.PROJECT_NAME){
			sb.append(".").append(beanName.toLowerName());
		}
		String servers = null;
		BindResult<String> result = binder.bind(sb.toString().trim(),String.class);
		if(null == result){
			return servers;
		}
		try {
			servers = result.get().trim();
		}catch (Exception e){}
		finally {
			logger.info("start redis cluster loading property=[{}],servers=[{}]",sb.toString(), servers);
		}
		return servers;


	}

}
